﻿using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Web;
using web_uchet.Models;
using System.Text;
using System.Linq.Expressions;

namespace web_uchet.Reports.OLAP
{
    /// <summary>
    /// Класс для получения значений показателей
    /// </summary>
    public class Index
    {
        public Index(OLAPFilters Filter)
        {
            //Index._IndexPropertiesDict.Add(typeof(Заказ), new Dictionary<Показатели, string>());
            //Dictionary<Показатели, string> D = Index._IndexPropertiesDict[typeof(Заказ)];
            //D.Add(Показатели.Продажи, "Цена_Услуги");
            this._Filter = Filter;
            if (this._Filter.Колличество_Заказов.HasValue)
            {
                ParameterExpression PF = Expression.Parameter(typeof(int), "Filter");
                ParameterExpression PA = Expression.Parameter(typeof(int), "Actual");
                Expression CountExpression = null;
                switch (this._Filter.Колличество_Заказов_Условие)
                {
                    case Условие.Больше:
                        CountExpression = Expression.GreaterThan(PA, PF);
                        break;
                    case Условие.БольшеИлиРавно:
                        CountExpression = Expression.GreaterThanOrEqual(PA, PF);
                        break;
                    case Условие.Меньше:
                        CountExpression = Expression.LessThan(PA, PF);
                        break;
                    case Условие.МеньшеИлиРавно:
                        CountExpression = Expression.LessThanOrEqual(PA, PF);
                        break;
                    case Условие.Равно:
                        CountExpression = Expression.Equal(PA, PF);
                        break;
                }
                this._CountFilter =
                    Expression.Lambda<Func<int, int, bool>>(CountExpression, new ParameterExpression[] { PF, PA })
                        .Compile();
            }
            else this._CountFilter = (PF, PA) => true;

            if (this._Filter.Продажи.HasValue)
            {
                ParameterExpression PF = Expression.Parameter(typeof(float), "Filter");
                ParameterExpression PA = Expression.Parameter(typeof(float), "Actual");
                Expression SaleExpression = null;
                switch (this._Filter.Продажи_Условие)
                {
                    case Условие.Больше:
                        SaleExpression = Expression.GreaterThan(PA, PF);
                        break;
                    case Условие.БольшеИлиРавно:
                        SaleExpression = Expression.GreaterThanOrEqual(PA, PF);
                        break;
                    case Условие.Меньше:
                        SaleExpression = Expression.LessThan(PA, PF);
                        break;
                    case Условие.МеньшеИлиРавно:
                        SaleExpression = Expression.LessThanOrEqual(PA, PF);
                        break;
                    case Условие.Равно:
                        SaleExpression = Expression.Equal(PA, PF);
                        break;
                }
                this._SalesFilter =
                    Expression.Lambda<Func<float, float, bool>>(SaleExpression, new ParameterExpression[] { PF, PA })
                        .Compile();
            }
            else this._SalesFilter = (PF, PA) => true;
        }
        //private static Dictionary<Type, Dictionary<Показатели, string>> _IndexPropertiesDict
        //    = new Dictionary<Type, Dictionary<Показатели, string>>();
        //public static T GetFloatIndexProp<T>(object o, Type OType, Показатели П)
        //{
        //    return (T)Convert.ChangeType(
        //        OType.GetProperty(Index._IndexPropertiesDict[OType][П]).GetValue(o, null),typeof(T));
        //}
        private const string _NewLine = "<br />";
        private OLAPFilters _Filter;
        Func<int, int, bool> _CountFilter;
        Func<float, float, bool> _SalesFilter;
        public string DoEval(IEnumerable Data,bool isHTML,ПоказателиSettings Set)
        {
            StringBuilder Result = new StringBuilder();
            ///Don't check the Ienum Element type, just filter, cause IEnum can contain Elem of any type
            var Q = Data.OfType<Заказ>();
            int Count; float? Sales;
            if (Q.Count()!=0)
            {
                
                if (Set.Кол_во_Заказов)
                {              
                    Count=Q.Count();                    
                    if (this._CountFilter(this._Filter.Колличество_Заказов.HasValue?this._Filter.Колличество_Заказов.Value:0,Count))
                        Result.AppendFormat("{0}{1}", Count, Index._NewLine);
                }
                if (Set.Продажи)
                {
                    var GroupedByCurrency=Q.GroupBy(e=>e.Валюта);
                    foreach (var gr in GroupedByCurrency)
                    {
                        Sales = gr.Sum(e => e.Цена);

                        if (this._SalesFilter(this._Filter.Продажи.HasValue?this._Filter.Продажи.Value:0, Sales.HasValue?Sales.Value:0))
                            Result.AppendFormat("{0} {1} {2}", Sales.ToString(), gr.Key.Символ, Index._NewLine);
                    }
                }
                return Result.ToString();
            }
            else throw new NotSupportedException("Показатели подсчитываются только для заказов");
        }
    }
}
